package com.guigusuqi.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.guigusuqi.app.config.WxCodeAuthenticationToken;
import com.guigusuqi.app.dto.DeputyCardInfoDTO;
import com.guigusuqi.app.dto.UserInfoDTO;
import com.guigusuqi.app.entity.*;
import com.guigusuqi.app.entity.DTO.UserCardInfoDTO;
import com.guigusuqi.app.entity.PO.DeputyCardInfo;
import com.guigusuqi.app.entity.PO.UserCardInfo;
import com.guigusuqi.app.entity.VO.UserInfo;
import com.guigusuqi.app.mapper.WxUserMapper;
import com.guigusuqi.app.service.WxUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guigusuqi.app.utils.UserThreadLocal;
import com.guigusuqi.commonutils.utils.GetTokenByAuthorizationUtils;
import com.guigusuqi.commonutils.utils.JWTUtils;
import com.guigusuqi.commonutils.utils.RedisCache;
import com.guigusuqi.commonutils.vo.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author suqi
 * @since 2022-04-06
 */
@Service
public class WxUserServiceImpl extends ServiceImpl<WxUserMapper, WxUser> implements WxUserService
{
    @Resource
    private WxUserMapper wxUserMapper;

    @Lazy
    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private RedisCache redisCache;

    @Override
    public WxUser getUserInfoByOpenId(String openid)
    {
        return wxUserMapper.getUserInfoByOpenId(openid);
    }

    @Override
    public String wxLogin(String openid)
    {
        // 用户验证
        Authentication authentication = null;

        //通过openid进行一个授权,这里需要修改userDetailService为微信小程序认证的方式
        try
        {
            /**
             * 1.通过WxCodeAuthenticationToken类将openid封装成WxCodeAuthenticationToken，principal=openid
             * 2.WxCodeAuthenticationSecurityConfig设置WxUserDetailsServiceImpl和wxCodeAuthenticationProvider
             *
             * 4.WxCodeAuthenticationProvider.supports,如果传过来的authentication是WxCodeAuthenticationToken就启用该provider
             * 5.WxUserDetailsServiceImpl通过openid从数据库中查询wxuser,返回封装的loginUser(=userDetail)
             * 6.WxCodeAuthenticationProvider进行authenticate授权，直接将userDetailsService返回的userdetail返回
             * 7.通过返回的loginWxUser获取openid,保存在jwt中
             */
            authentication = authenticationManager.authenticate(new WxCodeAuthenticationToken(openid));
        } catch (Exception e)
        {
            throw new RuntimeException(e.getMessage());
        }

        //如果authenticationManager认证通过，拿到这个当前登录用户信息
        LoginWxUser loginWxUser = (LoginWxUser) authentication.getPrincipal();

        //通过loginWxUser获取openid，创建token
        String token = JWTUtils.createToken(loginWxUser.getUser().getOpenid());

        //保存在redis中
        redisCache.setCacheObject("TOKEN_"+token,loginWxUser);

        UserThreadLocal.put(loginWxUser.getUser());

        return token;
    }

    /**
     * token合法性校验
     * 是否为空、解析是否成功、redis是否存在
     * @param token
     * @return
     */
    @Override
    public LoginWxUser checkAndParseToken(String token)
    {
        if (StringUtils.isEmpty(token))
        {
            return null;
        }
        /*解析token*/
        Map<String, Object> stringObjectMap = JWTUtils.checkToken(token);
        if (stringObjectMap == null) {
            return null;
        }
        LoginWxUser loginWxUser = redisCache.getCacheObject("TOKEN_" + token);
        if(Objects.isNull(loginWxUser))
        {
            return null;
        }
        return loginWxUser;
    }

    @Override
    public Result modifyUserInfo(UserInfoDTO userInfoDTO) throws IOException
    {
        String token = GetTokenByAuthorizationUtils.getToken();
        LoginWxUser loginWxUser = redisCache.getCacheObject("TOKEN_"+token);
        String openid = loginWxUser.getUser().getOpenid();

        LambdaQueryWrapper<WxUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WxUser::getOpenid,openid);

        WxUser wxUser = new WxUser();
        wxUser.setNickname(userInfoDTO.getNickname());
        wxUser.setPhone(userInfoDTO.getPhone());
        int update = wxUserMapper.update(wxUser, queryWrapper);
        if(update >= 1)
        {
            WxUser wxUser1 = wxUserMapper.selectOne(queryWrapper);
            BeanUtils.copyProperties(wxUser1,userInfoDTO);
            return Result.success().data("rows",userInfoDTO);
        }else
        {
            return Result.fail().message("修改失败!");
        }
    }

    @Override
    public Result selectUserInfo() throws IOException
    {
        String token = GetTokenByAuthorizationUtils.getToken();
        LoginWxUser loginWxUser = redisCache.getCacheObject("TOKEN_"+token);
        WxUser user = loginWxUser.getUser();
        String openid = user.getOpenid();

        LambdaQueryWrapper<WxUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WxUser::getOpenid,openid);
        WxUser wxUser = wxUserMapper.selectOne(queryWrapper);

        UserInfo userInfo = new UserInfo();
        userInfo.setImage(wxUser.getImage());
        userInfo.setNickName(wxUser.getNickname());
        userInfo.setPhone(wxUser.getPhone());

        return Result.success().data("row",userInfo);
    }

    @Override
    public UserCardInfo checkUserIsUserCard(String openid,String phone)
    {
        UserCardInfo userCardInfo = new UserCardInfo();
        // 通过phone查询主卡是否有这个用户,如果有 返回对应的userCardId
        String userCardId = wxUserMapper.selectUserCardByPhone(phone);

        if (StringUtils.isNotEmpty(userCardId)) // 说明他是主卡会员
        {
            // 再看user_user_card这张表是否有这个用户的会员记录 如果没有就直接添加一条记录

            // 获得主卡id
            List<String> userCardIdList = wxUserMapper.checkUserIsUserCard(openid);

            if (userCardIdList.size() == 0)
            {
                userCardInfo.setIsUserCard(true);
                wxUserMapper.insertUserCard(openid,userCardId);
                UserCard userCard = wxUserMapper.getUserCard(userCardId);
                userCardInfo.setUserCard(userCard);
            }else // 说明数据库已有记录 不用重新插入
            {
                userCardInfo.setIsUserCard(true);
                UserCard userCard = wxUserMapper.getUserCard(userCardId);
                userCardInfo.setUserCard(userCard);
            }
        }else
        {
            userCardInfo.setIsUserCard(false);
            userCardInfo.setUserCard(null);
        }

        return userCardInfo;
    }

    @Override
    public DeputyCardInfo selectDeputyCardByUserCardId(String userCardId)
    {
        DeputyCardInfo deputyCardInfo = new DeputyCardInfo();

        List<DeputyCardInfoDTO> list = wxUserMapper.selectDeputyCardByUserCardId(userCardId);

        if (list.size() == 0) // 说明没有对应的副卡
        {
            deputyCardInfo.setIsDeputyCard(false);
            deputyCardInfo.setDeputyCardList(null);
        }else {
            deputyCardInfo.setIsDeputyCard(false);
            deputyCardInfo.setDeputyCardList(list);
        }
        return deputyCardInfo;
    }


    @Override
    public DeputyCardInfo checkUserIsDeputyCard(String phone)
    {
        DeputyCardInfo deputyCardInfo = new DeputyCardInfo();

        // 获得副卡id
        List<String> deputyCardIdList = wxUserMapper.checkUserIsDeputyCard(phone);
        if (deputyCardIdList.size() == 0)
        {
            deputyCardInfo.setIsDeputyCard(false);
            deputyCardInfo.setDeputyCardList(null);
        }else
        {
            deputyCardInfo.setIsDeputyCard(true);
//            List<DeputyCard> deputyCardList = wxUserMapper.getDeputyCard(deputyCardIdList.get(0));
            List<DeputyCardInfoDTO> list = new ArrayList<>();
            DeputyCardInfoDTO deputyCardInfoDTO = new DeputyCardInfoDTO();
            String name = wxUserMapper.getDeputyCardNameByPhone(phone);
            deputyCardInfoDTO.setName(name);
            deputyCardInfoDTO.setPhone(phone);

            list.add(deputyCardInfoDTO);
            deputyCardInfo.setDeputyCardList(list);
        }
        return deputyCardInfo;
    }

    @Override
    public UserCardInfo selectUserCardByDeputyCardPhone(String phone)
    {
        UserCard userCard = wxUserMapper.selectUserCardByDeputyCardPhone(phone);

        UserCardInfo userCardInfo = new UserCardInfo();
        userCardInfo.setIsUserCard(false);
        userCardInfo.setUserCard(userCard);
        return userCardInfo;
    }

    @Override
    public Result getUserCardInfo() throws IOException
    {
        String token = GetTokenByAuthorizationUtils.getToken();
        LoginWxUser loginWxUser = redisCache.getCacheObject("TOKEN_"+token);
        WxUser wxUser = loginWxUser.getUser();
        String openid = wxUser.getOpenid();
        // 这里注意，有可能token存的是没有手机号的用户，如果他改了手机号，那就获取不了了,需要重新查一遍
        LambdaQueryWrapper<WxUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WxUser::getOpenid,openid);
        WxUser updateWxUser = wxUserMapper.selectOne(queryWrapper);
        final String phone = updateWxUser.getPhone();

        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(openid))
        {
            return Result.fail().message("手机号和openid不能为空!");
        }
        // 查看是否是主卡用户,如果有的话通过phone获取用户对应的主卡
        UserCardInfo userCardInfo = checkUserIsUserCard(openid,phone);

        UserCardInfoDTO userCardInfoDTO = new UserCardInfoDTO();
        // 如果是主卡用户
        // 1、显示主卡信息和所有副卡信息
        // 2、显示主副卡的消费（积分）记录
        // 3、可以分享副卡
        if (userCardInfo.getIsUserCard())
        {
            userCardInfoDTO.setUserCardInfo(userCardInfo);

            // 通过主卡id获取主卡对应的副卡信息
            DeputyCardInfo deputyCardInfo = selectDeputyCardByUserCardId(userCardInfo.getUserCard().getId());
            userCardInfoDTO.setDeputyCardInfo(deputyCardInfo);
            userCardInfoDTO.setIsMember(true);
        }else // 如果不是主卡用户，查看是否是副卡用户
        {
            DeputyCardInfo deputyCardInfo = checkUserIsDeputyCard(phone);

            if (deputyCardInfo.getIsDeputyCard())
            {
                userCardInfoDTO.setDeputyCardInfo(deputyCardInfo);

                // 再获取副卡对应的主卡信息
                // 同一个主卡的副卡cardNum都是一样的
                UserCardInfo userCardInfo2 = selectUserCardByDeputyCardPhone(phone);
                userCardInfoDTO.setUserCardInfo(userCardInfo2);
                userCardInfoDTO.setIsMember(true);
            }else // 不是会员
            {
                userCardInfoDTO.setIsMember(false);
                return Result.success().message("请线下联系门店开通会员").data("userCardInfo",userCardInfoDTO);
            }
        }
        return Result.success().data("userCardInfo",userCardInfoDTO);
    }
}
